/**
 * TODO: use the mx_typeof() to hold the shift operation (1 << n), e.g.:
 *       #define SETBIT(var, idx) { (var) |= (mx_typeof(var))1 << idx; }
 */

#ifndef __BIT_H
#define __BIT_H
#include "stdtype.h"

/**
 * basic data type processing
 */

#if (MX_CPU_BITWIDE == 32)
/* set the bit to 1 */
#define SETBIT(var, index) ((var) |= (0x01U << (index)))
/* clear the bit to 0 */
#define CLSBIT(var, index) ((var) &= (~(0x01U << (index))))
/* fill in the specified range with specified data. */
#define FILRNG(var, maxindex, minindex, value) ((var) = ((((var) & (((value) << (minindex)) | ((~(0xffffffffU << (minindex))) & (var)))) | ((value) << (minindex))) | (((var) >> ((maxindex) + 1)) << ((maxindex) + 1))))
#else
/* set the bit to 1 */
#define SETBIT(var, index) ((var) |= (0x01ULL << (index)))
/* clear the bit to 0 */
#define CLSBIT(var, index) ((var) &= (~(0x01ULL << (index))))
/* fill in the specified range with specified data. */
#define FILRNG(var, maxindex, minindex, value) ((var) = ((((var) & (((mx_uint64_t)(value) << (minindex)) | ((~(0xffffffffffffffffULL << (minindex))) & (var)))) | ((mx_uint64_t)(value) << (minindex))) | (((var) >> ((maxindex) + 1)) << ((maxindex) + 1))))
#endif

/* get the bit */
#define GETBIT(var, index) (((var) >> (index)) & 0x01U)
/* flip the bit */
#define FLPBIT(var, index) (GETBIT(var, index) == 1 ? CLSBIT(var, index) : SETBIT(var, index))
/* copy bit from `src` to `dest` */
#define CPYBIT(dest, src, idx) { if (GETBIT(src, idx) == 1) SETBIT(dest, idx); else CLSBIT(dest, idx); }

/**
 * bit mask processing, the masked bit can be operation
 */

#if (MX_CPU_BITWIDE == 32)
/* get the mask by index */
#define BITMSK(index) (1U << (index))
/* get the mask by index range, as long as (end - start) is less than 32 */
#define RNGMSK(end, start) ((0xFFFFFFFFU >> (32 - ((end) - (start) + 1))) << (start))
/* fill the specified data which start at 0 with bit mask */
#define FILMSKS(var, mask, value) ((var) = (((var) & (~(mask))) | (((value) << bit_lsbidx(mask)) & (mask))))
#else
/* get the mask by index */
#define BITMSK(index) (1ULL << (index))
/* get the mask by index range, as long as (end - start) is more than 32 */
#define RNGMSK(end, start) ((0xFFFFFFFFFFFFFFFFULL >> (64 - ((end) - (start) + 1))) << (start))
/* fill the specified data which start at 0 with bit mask */
#define FILMSKS(var, mask, value) ((var) = (((var) & (~(mask))) | (((mx_uint64_t)(value) << bit_lsbidx(mask)) & (mask))))
#endif

/* set the bit value of the mask bit to 1 */
#define SETMSK(var, mask) ((var) |= (mask))
/* clear the bit value of the mask bit to 0 */
#define CLSMSK(var, mask) ((var) &= (~(mask)))
/* get the value by bit mask */
#define GETMSK(var, mask) ((var) & (mask))
/* fill the specified data with bit mask */
#define FILMSK(var, mask, value) ((var) = (((var) & (~(mask))) | ((value) & (mask))))
/* get the value by bit mask and shift it to start at address 0 */
#define GETMSKS(var, mask) (((var) & (mask)) >> bit_lsbidx(mask))

/* get the lsb index */
mx_uint8_t bit_lsbidx (mx_usize_t dat);

/**
 * this function will iterate the specified variable
 * @prototype: void mx_bit_foreachi (stdtype, <b>, <i>, {...});
 * @note: can't change the bit value of src by <b>
 */
#define mx_bit_foreachi(var, b, i, ...) {   \
    mx_uint8_t b;   \
    mx_uint8_t bitwide = (mx_uint8_t)sizeof(var) << 3;  \
    for (mx_usize_t i = 0; i < bitwide; i++) {  \
        b = GETBIT(var, i); \
        __VA_ARGS__ \
    }   \
}

#endif
